package com.yance.fim.websocket;

import com.alibaba.fastjson.JSON;
import com.yance.fim.dto.WsMessageRequest;
import com.yance.fim.utils.CommandValue;
import com.yance.fim.utils.CommandStateConstants;
import com.yance.fim.utils.Utils;
import com.yance.fim.websocket.handler.ImExecptionHandler;
import com.yance.fim.websocket.msgqueue.DataPacketEventQueueHelper;
import com.yance.fim.websocket.packet.DataPacket;
import org.nustaq.serialization.FSTConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.tio.core.ChannelContext;
import org.tio.http.common.HttpRequest;
import org.tio.http.common.HttpResponse;
import org.tio.websocket.common.WsRequest;
import org.tio.websocket.common.WsSessionContext;
import org.tio.websocket.server.handler.IWsMsgHandler;

/**
 * @author yance
 */
@Service
public class FimWsMsgHandler implements IWsMsgHandler {

    private static Logger log = LoggerFactory.getLogger(FimWsMsgHandler.class);

    @Autowired
    private FSTConfiguration fstConfiguration;

    @Autowired
    private DataPacketEventQueueHelper seriesDataEventQueueHelper;

    /**
     * 握手时走这个方法，业务可以在这里获取cookie，request参数等
     *
     * @param request
     * @param httpResponse
     * @param channelContext
     * @return
     */
    @Override
    public HttpResponse handshake(HttpRequest request, HttpResponse httpResponse, ChannelContext channelContext) {
        String clientip = request.getClientIp();
        log.info("收到来自{}的ws握手包\r\n{}", clientip, request.toString());
        return httpResponse;
    }

    /**
     * 握手后走这个方法
     *
     * @param httpRequest
     * @param httpResponse
     * @param channelContext
     */
    @Override
    public void onAfterHandshaked(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) {

    }

    /**
     * 字节消息（binaryType = arraybuffer）过来后会走这个方法
     *
     * @param wsRequest
     * @param bytes
     * @param channelContext
     * @return
     */
    @Override
    public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) {
        return null;
    }

    /**
     * 当客户端发close flag时，会走这个方法
     *
     * @param wsRequest
     * @param bytes
     * @param channelContext
     * @return
     */
    @Override
    public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) {
        preHandle(wsRequest, bytes, channelContext);
        return null;
    }

    /**
     * 字符消息（binaryType = blob）过来后会走这个方法
     *
     * @param wsRequest
     * @param message
     * @param channelContext
     * @return
     */
    @Override
    public Object onText(WsRequest wsRequest, String message, ChannelContext channelContext) {
        preHandle(wsRequest, message, channelContext);
        return null;
    }

    private void preHandle(WsRequest wsRequest, Object packetData, ChannelContext channelContext) {
        WsSessionContext wsSessionContext = (WsSessionContext) channelContext.get();
        //获取websocket握手包
        HttpRequest httpRequest = wsSessionContext.getHandshakeRequest();
        //获取客户端Ip
        String clientIp = httpRequest.getClientIp();
        //接收到web端发送的消息
        try {
            WsMessageRequest wsMessageRequest = (packetData instanceof String) ? JSON.parseObject((String) packetData, WsMessageRequest.class) : (WsMessageRequest) fstConfiguration.asObject((byte[]) packetData);
            //收到客户端心跳包
            if (wsMessageRequest.getCommand() == CommandValue.HEARTBEAT_VALUE) {
                return;
            }
            log.warn("收到客户端 IP为:{},消息为:{}", clientIp, JSON.toJSONString(wsMessageRequest.getBody()));
            DataPacket dataPacket = createPushPacket(wsMessageRequest,channelContext);
            seriesDataEventQueueHelper.publishEvent(dataPacket);
        } catch (Exception e) {
            Utils.ConsoleExecptionLog(e);
            ImExecptionHandler.ImExecptionClose(channelContext, CommandStateConstants.DATAPACKET_ANALYSIS_EXCEPTION);
        }
    }

    /**
     * 创建分发数据包
     *
     * @param wsMessageRequest
     * @param channelContext
     * @return
     */
    private DataPacket createPushPacket(WsMessageRequest wsMessageRequest, ChannelContext channelContext) {
        DataPacket dataPacket = new DataPacket();
        dataPacket.setCommand(wsMessageRequest.getCommand());
        dataPacket.setBody(fstConfiguration.asByteArray(wsMessageRequest.getBody()));
        dataPacket.setChannelContext(channelContext);
        return dataPacket;
    }
}
